﻿using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using Sgml;

namespace PoshHttp
{
   public class Utility
   {
      /// <summary>
      /// Convert args array to a String, List&lt;String&gt; Hashtable
      /// </summary>
      /// <param name="arguments"></param>
      /// <returns></returns>
      public static Hashtable ArgumentsToHashtable(string[] arguments)
      {
         return new Hashtable(ArgumentsToDictionary(arguments));
      }

      /// <summary>
      /// Convert args array to a Dictionary
      /// </summary>
      /// <param name="arguments"></param>
      /// <returns></returns>
      public static Dictionary<string, List<string>> ArgumentsToDictionary(string[] arguments)
      {
         Dictionary<string, List<string>> dic = new Dictionary<string, List<string>>();
         // 1 or 2 - or a / followed by the name which doesn't start with - or have any = or : followed by a value ...
         Regex Spliter = new Regex("(?:^-{1,2}|^/)(?<name>[^-][^=:]*)(?:[=:](?<value>.*))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
         Regex Remover = new Regex("^[\'\"]?(.*?)[\'\"]?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
         string Parameter = null;
         Match Parts;
         if (arguments != null)
         {
            // Valid parameters forms:
            // {-,/,--}param{ ,=,:}((",')value(",'))
            // Examples: -param1 value1 --param2 /param3:"Test-:-work" /param4=happy -param5 '--=nice=--'
            foreach (string Txt in arguments)
            {
               // Look for new parameters (-,/ or --) and a possible enclosed value (=,:)
               Parts = Spliter.Match(Txt);

               if (!Parts.Success)
               {
                  if (Parameter != null)
                  {
                     // Found a value (for the last parameter found (space separator))
                     if (!dic.ContainsKey(Parameter))
                     {
                        dic[Parameter] = new List<string>();
                     }
                     dic[Parameter].Add(Remover.Replace(Txt, "$1"));
                     Parameter = null;
                  }
               }
               else if (Parts.Groups["value"].Success)
               {
                  if (Parameter != null)
                  {
                     if (!dic.ContainsKey(Parameter))
                     {
                        dic[Parameter] = new List<string>();
                     }

                     dic[Parameter].Add("true");
                     Parameter = null;
                  }
                  if (!dic.ContainsKey(Parts.Groups["name"].Value))
                  {
                     dic[Parts.Groups["name"].Value] = new List<string>();
                  }
                  dic[Parts.Groups["name"].Value].Add( Remover.Replace(Parts.Groups["value"].Value, "$1") );
               }
               else if (Parts.Groups["name"].Success)
               {
                  if (Parameter != null)
                  {
                     if (!dic.ContainsKey(Parameter))
                     {
                        dic[Parameter] = new List<string>();
                     }

                     dic[Parameter].Add("true");
                     Parameter = null;
                  }
                  Parameter = Parts.Groups["name"].Value;
               }
            }
            // In case a parameter is still waiting
            if (Parameter != null)
            {
               if (!dic.ContainsKey(Parameter))
               {
                  dic[Parameter] = new List<string>();
               }

               dic[Parameter].Add("true");
               Parameter = null;
            }
         }
         return dic;
      }

      /// <summary>
      /// Convert args array to a NameValueCollection
      /// </summary>
      /// <param name="arguments"></param>
      /// <returns></returns>
      public static NameValueCollection ArgumentsToNameValueCollection(string[] arguments)
      {
         NameValueCollection nvc = new NameValueCollection();
         // 1 or 2 - or a / followed by the name which doesn't start with - or have any = or : followed by a value ...
         Regex Spliter = new Regex("(?:^-{1,2}|^/)(?<name>[^-][^=:]*)(?:[=:](?<value>.*))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
         Regex Remover = new Regex("^[\'\"]?(.*?)[\'\"]?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
         string Parameter = null;
         Match Parts;
         if (arguments != null)
         {
            // Valid parameters forms:
            // {-,/,--}param{ ,=,:}((",')value(",'))
            // Examples: -param1 value1 --param2 /param3:"Test-:-work" /param4=happy -param5 '--=nice=--'
            foreach (string Txt in arguments)
            {
               // Look for new parameters (-,/ or --) and a possible enclosed value (=,:)
               Parts = Spliter.Match(Txt);

               if (!Parts.Success)
               {
                  if (Parameter != null)
                  {
                     // Found a value (for the last parameter found (space separator))
                     nvc.Add(Parameter,Remover.Replace(Txt, "$1"));
                     Parameter = null;
                  }
               }
               else if (Parts.Groups["value"].Success)
               {
                  // we found a new parameter, if there's an old one, then it's a switch
                  if (Parameter != null)
                  {
                     nvc.Add(Parameter,"true");
                     Parameter = null;
                  }
                  nvc.Add(Parts.Groups["name"].Value, Remover.Replace(Parts.Groups["value"].Value, "$1"));
               }
               else if (Parts.Groups["name"].Success)
               {
                  if (Parameter != null)
                  {
                     nvc.Add(Parameter,"true");
                     Parameter = null;
                  }
                  Parameter = Parts.Groups["name"].Value;
               }
            }
            // In case a parameter is still waiting
            if (Parameter != null)
            {
               nvc.Add(Parameter,"true");
               Parameter = null;
            }
         }
         return nvc;
      }

      /// <summary>
      /// Convert a NameValueCollection into a  String, List&lt;String&gt; Hashtable
      /// </summary>
      /// <param name="nvc"></param>
      /// <returns></returns>
      public static Hashtable ToHashtable(NameValueCollection nvc)
      {
         return new Hashtable(ToDictionary(nvc));
      }

      /// <summary>
      /// Convert a NameValueCollection into a Dictionary
      /// </summary>
      /// <param name="nvc"></param>
      /// <returns></returns>
      public static Dictionary<string, List<string>> ToDictionary(NameValueCollection nvc)
      {
         Dictionary<string, List<string>> dic = new Dictionary<string, List<string>>();
         foreach (string key in nvc.Keys)
         {
            dic[key] = new List<string>(nvc.GetValues(key));
         }
         return dic;
      }

      /// <summary>
      /// Convert an Http Query String into a Dictionary
      /// </summary>
      /// <param name="query"></param>
      /// <returns></returns>
      public static Dictionary<string, List<string>> ParseQueryStringAsDictionary(string query)
      {
         return ToDictionary(System.Web.HttpUtility.ParseQueryString(query));
      }

      /// <summary>
      /// Convert an Http Query String into a String, List&lt;String&gt; Hashtable
      /// </summary>
      /// <param name="query"></param>
      /// <returns></returns>
      public static Hashtable ParseQueryString(string query)
      {
         return new Hashtable(ToDictionary(System.Web.HttpUtility.ParseQueryString(query)));
      }

      /// <summary>
      /// Convert a NameValueCollection into an Http Query String 
      /// and UrlEncode the data
      /// </summary>
      /// <param name="data"></param>
      /// <returns></returns>
      public static string BuildQueryString(NameValueCollection data)
      {
         StringBuilder result = new StringBuilder();
         foreach (string key in data.Keys)
         {
            foreach (string value in data.GetValues(key))
            {
               result.AppendFormat("{0}={1}&",
                  System.Web.HttpUtility.UrlEncode(key),
                  System.Web.HttpUtility.UrlEncode(value));
            }
         }
         // don't return that last ampersand (&)
         return result.ToString(0, result.Length - 1);
      }

      /// <summary>
      /// Convert a Hashtable into an Http Query String 
      /// and UrlEncode the data
      /// </summary>
      /// <param name="data"></param>
      /// <returns></returns>
      public static string BuildQueryString(Hashtable data)
      {
         StringBuilder result = new StringBuilder();
         foreach (var key in data.Keys)
         {
            if (data[key] is ICollection )
            {
               foreach (var value in data[key] as ICollection)
               {
                  result.AppendFormat("{0}={1}&",
                     System.Web.HttpUtility.UrlEncode(key.ToString()),
                     System.Web.HttpUtility.UrlEncode(value.ToString()));
               }
            }
            //else if (data[key] is IEnumerable)
            //{
            //   foreach (var value in data[key] as IEnumerable)
            //   {
            //      result.AppendFormat("{0}={1}&",
            //         System.Web.HttpUtility.UrlEncode(key.ToString()),
            //         System.Web.HttpUtility.UrlEncode(value.ToString()));
            //   }
            //}
            else
            {
               result.AppendFormat("{0}={1}&",
                  System.Web.HttpUtility.UrlEncode(key.ToString()),
                  System.Web.HttpUtility.UrlEncode(data[key].ToString()));
            }
         }
         // don't return that last ampersand (&)
         return result.ToString(0, result.Length - 1);
      }




      /// <summary>
      /// Parses the text as HTML and returns it as an XmlDocument
      /// </summary>
      /// <param name="html">The HTML source</param>
      /// <returns>An XmlDocument</returns>
      internal static XmlDocument ConvertHtml(string html)
      {
         XmlDocument doc = new XmlDocument();
         using (TextReader reader = new StringReader(html))
         {
            // Set the doctype as HTML so SgmlReader will use that...
            SgmlReader xmlReader = new SgmlReader();
            xmlReader.DocType = "HTML";
            xmlReader.HtmlTextReader = reader;
            doc.Load(xmlReader);
            reader.Close();
            xmlReader.Close();
         }
         return doc;
      }

      /// <summary>
      /// Parses the text from the reader and returns it as an XmlDocument
      /// </summary>
      /// <param name="htmlReader">The TextReader</param>
      /// <returns>An XmlDocument</returns>
      internal static XmlDocument ConvertHtml(TextReader htmlReader)
      {
         XmlDocument doc = new XmlDocument();

         // Set the doctype as HTML so SgmlReader will use that...
         SgmlReader xmlReader = new SgmlReader();
         xmlReader.DocType = "HTML";
         xmlReader.HtmlTextReader = htmlReader;
         doc.Load(xmlReader);
         xmlReader.Close();

         return doc;
      }
   }
}
